﻿// 3DPCL.cpp: 定义应用程序的入口点。
//

#include "playPCL.h"


MainWidget::MainWidget(QWidget* p) :QWidget(p), uiMain(new Ui::Form) {

	uiMain->setupUi(this);

	setWindowTitle("多视角稀疏三维重建Demo");

	initViewer();  // 初始化可视化窗口

    m_reconThread = new SparseRecontructor(this);
    
    // 连接信号槽（核心：主线程 ↔ 子线程）
    connect(m_reconThread,&SparseRecontructor::progressUpdate,this, &MainWidget::on_progressUpdate);
    connect(m_reconThread, &SparseRecontructor::reconstructFinished,this, &MainWidget::on_reconstructFinished);
    connect(m_reconThread, &SparseRecontructor::errorOccurred,this, &MainWidget::on_errorOccurred);

}

MainWidget::~MainWidget() {
    m_reconThread->stop();
    m_reconThread->wait();
    delete m_reconThread;
	delete uiMain;
}


void MainWidget::initViewer() {

    // 1. 激活 Qt 控件的 OpenGL 上下文
    uiMain->qvtkWidget->makeCurrent();  

    // 2. 创建核心组件
    renderWindow->AddRenderer(renderer);
    uiMain->qvtkWidget->setRenderWindow(renderWindow); 

    renderer->SetBackground(0.1, 0.1, 0.1); // 深灰色背景

    //// 3. 创建测试用的圆锥模型
    //vtkNew<vtkConeSource> coneSource;  // 圆锥数据源
    //coneSource->SetHeight(3.0);        // 圆锥高度
    //coneSource->SetRadius(1.0);        // 圆锥底部半径
    //coneSource->SetResolution(30);     // 分辨率（边数）

    //// 4. 创建映射器（将数据转换为图形基元）
    //vtkNew<vtkPolyDataMapper> coneMapper;
    //coneMapper->SetInputConnection(coneSource->GetOutputPort());

    //// 5. 创建演员（负责渲染）
    //vtkNew<vtkActor> coneActor;
    //coneActor->SetMapper(coneMapper);
    //coneActor->GetProperty()->SetColor(0.8, 0.2, 0.2);  // 红色

    //// 6. 将演员添加到渲染器
    //renderer->AddActor(coneActor);

    //// 7. 设置相机位置（确保模型可见）
    //renderer->ResetCamera();  // 自动调整相机以显示所有对象


    // 8. 配置交互器
    vtkNew<vtkGenericRenderWindowInteractor> interactor;
    interactor->SetRenderWindow(renderWindow);

    vtkNew<vtkInteractorStyleTrackballCamera> style;
    interactor->SetInteractorStyle(style); // 支持旋转、缩放等操作

    interactor->Initialize();
    renderWindow->Render();

    qDebug() << "VTK 版本：" << VTK_MAJOR_VERSION << "." << VTK_MINOR_VERSION;

}

// 显示点云
void MainWidget::showPointCloud(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud)
{

    //空点云判断
    if (!cloud || cloud->empty()) {

        renderer->RemoveAllViewProps();
        renderWindow->Render();
        return;
    }

    //清除遗留的actors  VTK 8.x 接口
    renderer->RemoveAllViewProps();

    //创建VTK点集和颜色数组
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    vtkSmartPointer<vtkUnsignedCharArray> colors = vtkSmartPointer<vtkUnsignedCharArray>::New();
    colors->SetNumberOfComponents(3);
    colors->SetName("Colors");

    //遍历PCL点云，添加坐标和颜色
    for (const auto& p : *cloud) {

        points->InsertNextPoint(p.x,p.y,p.z);
        double rgbDouble[3] = {
        static_cast<double>(p.r),  // unsigned char -> double
        static_cast<double>(p.g),
        static_cast<double>(p.b)
        };
        colors->InsertNextTuple(rgbDouble);
    }

    //构建多边形数据
    vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();
    polyData->SetPoints(points);
    polyData->GetPointData()->SetScalars(colors);

    //顶点渲染过滤器（将点转为可渲染的顶点）
    vtkSmartPointer<vtkVertexGlyphFilter> vertexFilter = vtkSmartPointer<vtkVertexGlyphFilter>::New();
    vertexFilter->SetInputData(polyData);
    vertexFilter->Update();

    //映射器+演员（设置点大小优化可视化效果）
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputData(vertexFilter->GetOutput());

    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
    actor->GetProperty()->SetPointSize(2.0);

    //添加到渲染器并更新相机
    renderer->AddActor(actor);
    renderer->ResetCamera();

    //更新渲染
    renderWindow->Render();

}



void MainWidget::on_selectImagesBtn_clicked() {


    //1、选择图片集

    QStringList OfileNames = QFileDialog::getOpenFileNames(
        this,
        tr("选择图片集(数量大于5)"),
        "",
        tr("图片文件（*.png *.jpg *.jpeg *.bmp）")
    );

    if (OfileNames.size() < 5) {

        QMessageBox::warning(this, tr("警告"), tr("请至少选择5张图片"));
        return;
    }

    //2、存储在标准容器中
    imagePaths.clear();
    for (const QString& fileName : OfileNames) {
        imagePaths.push_back(fileName.toStdString());
    }

    QMessageBox::information(this, tr("提升"), tr("已选择了 %1 张图片").arg(imagePaths.size()));

}


void MainWidget::on_reconstructBtn_clicked() {


    //1、检查图片数量
    if (imagePaths.size() < 5)
    {
        QMessageBox::warning(this, tr("警告"), tr("请至少上传5张图片"));
        return;
    }

    // 检查线程是否正在运行（避免重复点击）
    if (m_reconThread->isRunning()) {
        QMessageBox::warning(this, tr("提示"), tr("重建任务正在进行中，请稍后..."));
        return;
    }

    m_reconThread->setImagesPath(imagePaths);
    m_reconThread->start();// 启动线程（自动调用run()

}

void MainWidget::on_progressUpdate(int progress, const QString& status)
{

    qDebug() << "当前进度是："<< progress ;

}

void MainWidget::on_reconstructFinished(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud)
{

    // 立即将点云指针保存到主线程的成员变量（延长生命周期）
    m_pointCloud = cloud;

    showPointCloud(cloud);
    QMessageBox::information(this, tr("完成"),
        tr("三维稀疏建模完成，共生成 %1 个点").arg(cloud->size()));

}

void MainWidget::on_errorOccurred(const QString& errorMsg)
{
    QMessageBox::critical(this, tr("错误"), errorMsg);
}
